package com.xi.jetcomposedemo.ktx

import android.annotation.SuppressLint
import android.app.Activity
import android.app.Application
import android.content.*
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.PowerManager
import android.provider.Settings
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.Toast
import androidx.annotation.LayoutRes
import androidx.annotation.RequiresApi
import androidx.annotation.StringRes
import androidx.core.content.ContextCompat
import java.io.File
import java.io.FileInputStream
import java.io.IOException
import java.nio.charset.Charset


fun Context.toast(message: String, duration: Int = Toast.LENGTH_SHORT): Toast {
    return Toast.makeText(this, message, duration).apply { show() }
}

fun Context.toast(@StringRes resId: Int, duration: Int = Toast.LENGTH_SHORT): Toast {
    return Toast.makeText(this, resId, duration).apply { show() }
}

fun Context.inflateLayout(@LayoutRes layoutResId: Int, parent: ViewGroup? = null, attachToRoot: Boolean = false) = LayoutInflater.from(this).inflate(layoutResId, parent, attachToRoot)

fun Context.isPermissionGranted(permission: String): Boolean =
        ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED

fun Context.arePermissionsGranted(vararg permissions: String): Boolean =
        permissions.all { ContextCompat.checkSelfPermission(this, it) == PackageManager.PERMISSION_GRANTED }

inline fun <reified T : Activity> Context.startActivity(intentInit: Intent.() -> Unit = {}) {
    startActivity(Intent(this, T::class.java).apply { intentInit() })
}

inline fun Context.startActivity(intent: Intent, intentInit: Intent.() -> Unit = {}) {
    startActivity(intent.apply { intentInit() })
}

fun Context.getActivity(): Activity? {
    var context = this
    while (context is ContextWrapper) {
        if (context is Activity) {
            return context
        }
        context = context.baseContext
    }
    return null
}

inline fun Context.startLaunchActivity(init: Intent.() -> Unit = {}) {
    val intent = packageManager.getLaunchIntentForPackage(packageName) ?: return
    intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
    intent.init()
    startActivity(intent)
}

/**
 * 判断某进程是否存活
 */
fun Context.isProcessAlive(pid: Int): Boolean {
    return try {
        // 构造进程的proc目录路径
        val procDir = File("/proc/$pid")

        // 检查proc目录是否存在，存在则表示进程还存活
        procDir.exists()
    } catch (e: Exception) {
        e.printStackTrace()
        false
    }
}

/**
 * 判断当前进程名称是否为主进程
 */
fun Context.isMainProcess(): Boolean {
    val mainProcessName: String = this.getMainProcessName()
    if (TextUtils.isEmpty(mainProcessName)) {
        return true
    }
    val currentProcess = getCurrentProcessName()
    return TextUtils.isEmpty(currentProcess) || mainProcessName == currentProcess
}

/**
 * 获取主进程的名称
 */
private fun Context.getMainProcessName(): String {
    return return this.packageName
}

/**
 * 获得当前进程的名字
 */
fun getCurrentProcessName(): String? {
    try {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            return Application.getProcessName()
        }
        var currentProcess: String? = getCurrentProcessNameByCmd()
        if (TextUtils.isEmpty(currentProcess)) {
            currentProcess = getCurrentProcessNameByAT()
        }
        return currentProcess
    } catch (e: java.lang.Exception) {
        e.printStackTrace()
    }
    return null
}

private fun getCurrentProcessNameByCmd(): String? {
    var `in`: FileInputStream? = null
    try {
        val fn = "/proc/self/cmdline"
        `in` = FileInputStream(fn)
        val buffer = ByteArray(256)
        var len = 0
        var b: Int
        while (`in`.read().also { b = it } > 0 && len < buffer.size) {
            buffer[len++] = b.toByte()
        }
        if (len > 0) {
            return String(buffer, 0, len, Charset.forName("UTF-8"))
        }
    } catch (e: Throwable) {
        // ignore
    } finally {
        if (`in` != null) {
            try {
                `in`.close()
            } catch (e: IOException) {
                e.printStackTrace()
            }
        }
    }
    return null
}

private fun getCurrentProcessNameByAT(): String? {
    var processName: String? = null
    try {
        @SuppressLint("PrivateApi") val activityThread = Class.forName("android.app.ActivityThread", false, Application::class.java.classLoader)
        val declaredMethod = activityThread.getDeclaredMethod("currentProcessName", *arrayOfNulls<Class<*>?>(0))
        declaredMethod.isAccessible = true
        val processInvoke = declaredMethod.invoke(null)
        if (processInvoke is String) {
            processName = processInvoke
        }
    } catch (e: Throwable) {
        //ignore
    }
    return processName
}

fun Context.getAppVersion(): String? {
    try {
        val packageInfo = packageManager.getPackageInfo(packageName, 0)
        return packageInfo.versionName
    } catch (e: PackageManager.NameNotFoundException) {
        e.printStackTrace()
    }
    return null
}

fun Context.isScreenOn(): Boolean? {
    return powerManager?.isScreenOn
}

@SuppressLint("InvalidWakeLockTag")
fun Context.turnOnScreent() {
    val pm = powerManager
    pm?.let {
        val wl = pm.newWakeLock(
                PowerManager.FULL_WAKE_LOCK or PowerManager.ACQUIRE_CAUSES_WAKEUP
                        or PowerManager.ON_AFTER_RELEASE, "MyLock")
        wl.acquire(10000)
        val wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyCpuLock")
        wakeLock.acquire(10000)
    }
}

/**
 * 屏幕是否解锁
 */
fun Context.isScreenUnlocked(): Boolean? {
    return this.keyguardManager?.isKeyguardLocked == false
}

fun Context.isAppInstall(packageName: String): Boolean {
    val pinfo = packageManager.getInstalledPackages(0)
    return pinfo?.any { it.packageName == packageName } ?: false
}

/**
 * load file from assets resource of [fileName]
 */
fun Context.loadAsset(fileName: String): String? {
    try {
        return assets.open(fileName).bufferedReader().use { it.readText() }
    } catch (e: Exception) {
        e.printStackTrace()
    }
    return null
}

@Deprecated(message = "Difficult to read and communicate", replaceWith = ReplaceWith("context.copyToClipBoard"))
fun Context.copyString(str: String) {
    val clipBoard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
    clipBoard.setPrimaryClip(ClipData.newPlainText("video url", str))
}

/**
 * 复制到粘贴板
 */
fun Context.copyToClipBoard(text: String?, label: String = this.packageName) {
    if (text.isNullOrEmpty()) return
    clipboardManager?.setPrimaryClip(ClipData.newPlainText(label, text))
}

@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
fun Context.awakeApp(): Boolean {
    return activityManager.appTasks.getOrNull(0)?.moveToFront() != null
}

/**
 * 通过包名查询应用信息
 */
fun Context.getPackageInfo(appPackageName: String, isShowException: Boolean = true): PackageInfo? = try {
    packageManager.getPackageInfo(appPackageName, 0)
} catch (e: PackageManager.NameNotFoundException) {
    if (isShowException) {
        e.printStackTrace()
    }
    null
}

/**
 * 是否已忽略电池优化
 */
fun Context.isIgnoringBatteryOptimizations(): Boolean {
    val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager?
    return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        powerManager?.isIgnoringBatteryOptimizations(packageName) ?: false
    } else {
        true
    }
}

/**
 * 忽略电池优化
 */
fun Activity.ignoreBatteryOptimizations() {
    val intent = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)
    intent.data = Uri.parse("package:$packageName")
    startActivityForResult(intent, 1)
}

fun Context.appName(): String? {
    return try {
        val labelRes = this.applicationInfo.labelRes
        resources.getString(labelRes)
    } catch (e: Exception) {
        null
    }
}